﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace Mimoza.RdpPlugin
{
    public class PluginFileSync
    {
        public const string FilesPluginTag = "mimozafiletag:";
        public const string FilesPluginStartupTag = "mimozaisstartup:";
        public const string FilesPolicyStartupDelimer = "-S-";

        public PluginFileSync(string folderPath, string fileExt)
        {
            FolderPath = folderPath;
            FileExtention = fileExt;
        }

        public PluginFileSync(string fileExt)
        {
            FolderPath = Common.GlobalSettings.DesktopPath;
            FileExtention = fileExt;
        }

        public string FolderPath
        {
            get { return m_folderPath; }
            set { m_folderPath = value; }
        }

        public string FileExtention
        {
            get { return m_fileExtention; }
            set { m_fileExtention = value; }
        }

        public bool HasPolicyIdInPlainString
        {
            get { return m_bHasPolicyIdInPlainString; }
            set { m_bHasPolicyIdInPlainString = value; }
        } 

        public void Replace(string filePath)
        {
            string fileTo = GetFileName(filePath, FolderPath);
            string policyIdFrom = GetFilePolicyId(filePath);

            ReplaceFile(filePath, fileTo, policyIdFrom);
        }

        public void Remove(string filePath)
        {
            string policyIdFrom = Path.GetExtension(filePath).Substring(1);

            foreach (string fileName in Directory.GetFiles(FolderPath, "*." + FileExtention))
            {
                string policyIdTo = GetFilePolicyId(fileName);
                if (!string.IsNullOrEmpty(policyIdTo) && policyIdTo == policyIdFrom)
                {
                    File.Delete(fileName);
                }
            }
        }

        public void Do(string filesFolder)
        {
            Do(filesFolder, false);
        }

        public void Do(string filesFolder, bool bOnlyStartupField)
        {
            Directory.CreateDirectory(filesFolder);

            List<string> filesPolicyIds = new List<string>();
            foreach (string fileName in Directory.GetFiles(filesFolder, "*.*"))
            {
                bool bIsStrartup;
                string policyIdFrom = GetFilePolicyId(fileName, out bIsStrartup);
                if (string.IsNullOrEmpty(policyIdFrom)) continue;
                if (bOnlyStartupField && !bIsStrartup) continue;

                Replace(fileName);
                filesPolicyIds.Add(Path.GetExtension(fileName).Substring(1));
            }

            EraseNotExistsPluginFiles(filesPolicyIds, FolderPath);
        }

        private string GetFileName(string filePath, string folderPath)
        {
            string fileName = Path.GetFileNameWithoutExtension(filePath) + "." + FileExtention;

            return Path.Combine(folderPath, fileName);
        }

        private void ReplaceFile(string filePath, string fileTo, string policyIdFrom)
        {
            bool bFileReplace = true;
            int nameSuffixCount = 1;
            do
            {
                bFileReplace = true;
                fileTo = MakeCountedName(fileTo, nameSuffixCount);
                if (File.Exists(fileTo))
                {
                    string policyIdTo = GetFilePolicyId(fileTo);
                    if (!string.IsNullOrEmpty(policyIdTo) && policyIdTo != policyIdFrom)
                    {
                        bFileReplace = false;
                        nameSuffixCount++;
                    }
                }

                if (bFileReplace)
                {
                    File.Copy(filePath, fileTo, true);
                    ErasePolicyFile(fileTo, policyIdFrom);
                }
            }
            while (!bFileReplace);
        }

        private void EraseNotExistsPluginFiles(List<string> filesPolicyIds, string folderPath)
        {
            try
            {
                foreach (string fileName in Directory.GetFiles(folderPath, "*." + FileExtention))
                {
                    string policyIdTo = GetFilePolicyId(fileName);
                    if (string.IsNullOrEmpty(policyIdTo)) continue;

                    int index = filesPolicyIds.FindIndex(polId => polId == policyIdTo);
                    if (index<0)
                    {
                        File.Delete(fileName);
                    }
                }
            }
            catch (System.Exception e)
            {
                Common.Logger.Log.Error("Mimoza.PluginFileSync: error in erase desktop file. folderPath - '" + folderPath + "'\nError - '" +
                    e.ToString() + "'.");
            }
        }

        private void ErasePolicyFile(string exceptFileTo, string policyIdFrom)
        {
            try
            {
                foreach (string fileName in Directory.GetFiles(FolderPath, "*." + FileExtention))
                {
                    if (exceptFileTo == fileName) continue;

                    string policyIdTo = GetFilePolicyId(fileName);
                    if (string.IsNullOrEmpty(policyIdTo)) continue;

                    if (policyIdTo==policyIdFrom)
                    {
                        File.Delete(fileName);
                    }
                }
            }
            catch (System.Exception e)
            {
                Common.Logger.Log.Error("Mimoza.RdpPlugin: error in erase policy desktop file. Error - '" +
                    e.ToString() + "'.");
            }
        }

        private static bool IsPluginFile(string filePath)
        {
            using (TextReader reader = new StreamReader(filePath))
            {
                string text = reader.ReadToEnd();
                return text.Contains(FilesPluginTag) ? true : false;
            }
        }

        private string GetFilePolicyId(string filePath)
        {
            bool bIsStartup;
            return GetFilePolicyId(filePath, out bIsStartup);
        }

        private string GetFilePolicyId(string filePath, out bool bIsStartup)
        {
            const string c_FileTag = FilesPluginTag;
            const string c_FileStartupTag = FilesPluginStartupTag;
            const int c_PolicyIdLen = 36;

            string policyId = "";
            bIsStartup = false;

            try
            {
                using (TextReader reader = new StreamReader(filePath))
                {
                    string fileText = reader.ReadToEnd();

                    if (HasPolicyIdInPlainString)
                    {
                        int delimerPos = fileText.IndexOf(FilesPolicyStartupDelimer);
                        if (delimerPos >= 0)
                        {
                            bIsStartup = (0 != int.Parse(fileText.Substring(delimerPos + FilesPolicyStartupDelimer.Length, 1)));

                            policyId = fileText.Substring(delimerPos - c_PolicyIdLen, c_PolicyIdLen);
                        }
                    }
                    else
                    {
                        int pos = fileText.IndexOf(c_FileTag);
                        if (pos >= 0)
                        {
                            policyId = fileText.Substring(pos + c_FileTag.Length, c_PolicyIdLen);
                        }
                        pos = fileText.IndexOf(c_FileStartupTag);
                        if (pos >= 0)
                        {
                            bIsStartup = (0 != int.Parse(fileText.Substring(pos + c_FileStartupTag.Length, 1)));
                        }
                    }
                }
            }
            catch (System.Exception)
            {
            }

            return policyId;
        }

        private static string MakeCountedName(string fileName, int count)
        {
            if (count <= 1) return fileName;

            string fileNameWithExtent = Path.Combine(Path.GetDirectoryName(fileName),
                Path.GetFileNameWithoutExtension(fileName));

            fileName = fileNameWithExtent + "(" + count.ToString() + ")" +
                Path.GetExtension(fileName);

            return fileName;
        }

        string m_folderPath;
        string m_fileExtention;
        bool m_bHasPolicyIdInPlainString = false;
    }
}
